<?php
/******************************************************************************************

	Copyright (C) 2007, 2008 da3rX (i.r.da3rx@gmail.com)

	This file is part of decode explorer.

	Decode explorer is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Decode explorer is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with decode explorer.  If not, see <http://www.gnu.org/licenses/>.

******************************************************************************************/


if(!defined('DECODE_EXPLORER'))
	die('DECODE_EXPLORER constant not defined.');


/* Returns the files array (table body, file count, total file size) */
function d_files()
{
	global $dir, $opendirectly, $newwindow, $code;
	
	//Variables
	$files = d_files_array();
	$number = 0;
	$totalfilesize = 0;
	
	//Start the output buffer
	ob_start();
	
	foreach($files as $file) {
		//Variables
		$path = (empty($dir) ? $file['name'] : $dir . '/' . $file['name']);
		$is_dir = is_dir($path);
		$icon = ($is_dir ? 'folder.png' : d_icon($file['name']));
		$parsedpath = str_replace('%2F', '/', rawurlencode($path));
		$opendirectly_cache = in_array($file['name'], $opendirectly);
		$code_cache = in_array(d_fileextension($file['name']), $code);
		$titletag = '';
		
		$filename = $file['name'];
		
		if(!is_utf8($filename))
			$filename = utf8_encode($filename);
		$filename = htmlspecialchars($filename);
		
		if(strlen_utf8($file['name']) > 50) {
			if($is_dir)
				$filename = substr_utf8($file['name'], 0, 47) . '...';
			else {
				$fileextension = d_fileextension($file['name']);
				$filename = substr_utf8($file['name'], 0, 47 - strlen_utf8($fileextension)) . '...' . $fileextension;
			}
			$titletag = ' title="' . htmlspecialchars($file['name']) . '"';
		}
		
		
		if($is_dir)
			echo ($number == 0 ? '' : "\t\t") . '<tr class="' . ($number & 1 ? 'one' : 'two') . '" onclick="go(\'' . ($opendirectly_cache ? '' : '?dir=') . $parsedpath . '\')">' . "\r\n";
		else
			echo "\t\t" . '<tr class="' . ($number & 1 ? 'one' : 'two') . '"' . ($newwindow ? '' : ' onclick="go(\'' . ($code_cache ? '?code=' : '') . $parsedpath . '\')"') . '>' . "\r\n";
		
		echo "\t\t\t" . '<td><img src="decode/img/' . $icon . '" alt="*" /></td>' . "\r\n";
		
		if($is_dir)
			echo "\t\t\t" . '<td colspan="2"><a href="' . ($opendirectly_cache ? '' : '?dir=') . $parsedpath . '"' . ($titletag ? $titletag : '') . '>' . $filename . '</a></td>' . "\r\n";
		else {
			echo "\t\t\t" . '<td><a href="' . ($code_cache ? '?code=' : '') . $parsedpath . '"' . ($titletag ? $titletag : '') . ($newwindow ? ' target="_blank"' : '') . '>' . $filename . '</a></td>' . "\r\n";
			echo "\t\t\t" . '<td>' . d_filesizefrombytes($file['size']) . '</td>' . "\r\n";
			$totalfilesize += $file['size'];
		}
		
		echo "\t\t\t" . '<td>' . $file['modified'] . '</td>' . "\r\n";
		echo "\t\t" . '</tr>' . "\r\n";
		$number++;
	}
	
	//Returns the files count and their total size in bytes
	return array(
	'tbody' => ob_get_clean(),
	'filecount' => count($files),
	'totalfilesize' => $totalfilesize,
	);
}


/* Returns a sorted multidimensional array with all the file information (name, size, last modified date) */
function d_files_array()
{
	global $dir, $private;
	
	if(empty($dir))
		$dir = '.';
	
	$opendir = @opendir($dir);
	
	//Define the variables
	$dirs = array();
	$files = array();
	
	while(($filename = @readdir($opendir)) !== false)
		if(($filename{0} != '.') && !(empty($dir) && ($filename == 'index.php')) && !in_array($filename, $private)) {
			if(is_dir($dir . '/' . $filename))
				$dirs[] = $filename;
			else
				$files[] = $filename;
		}
	
	@closedir($dir);
		
	$dirsfiles = array_merge($dirs, $files);
	
	$files = array(); //Reset
	$count = count($dirsfiles);
	for($x = 0; $x < $count; $x++) {
		$files[$x]['name'] = $dirsfiles[$x];
		$files[$x]['size'] = filesize($dir . '/' . $dirsfiles[$x]);
		$files[$x]['modified'] = d_filemodified($dir . '/' . $dirsfiles[$x]);
	}
	
	/* Sorting */
	if(!empty($_GET['sort'])) {
		$sort = $_GET['sort'];
		
		//Icon
		if($sort == 'ia')
			$files = d_sort($files, 'icon', 'asc');
		elseif($sort == 'id')
			$files = d_sort($files, 'icon', 'desc');
		
		//Name
		elseif($sort == 'na')
			$files = d_sort($files, 'name', 'asc');
		elseif($sort == 'nd')
			$files = d_sort($files, 'name', 'desc');
		
		//Size
		elseif($sort == 'sa')
			$files = d_sort($files, 'size', 'asc');
		elseif($sort == 'sd')
			$files = d_sort($files, 'size', 'desc');
		
		//Modified
		elseif($sort == 'ma')
			$files = d_sort($files, 'modified', 'asc');
		elseif($sort == 'md')
			$files = d_sort($files, 'modified', 'desc');
		
		else //If $sort is invalid
			$files = d_sort($files, 'name', 'asc');
	}
	else //If $_GET['sort'] is empty
		$files = d_sort($files, 'name', 'asc');
	
	//Reset
	if($dir == '.')
		$dir = '';
	
	return $files;
}


/* Returns the file icon */
function d_icon($filename)
{
	global $icons;
	
	$fileextension = d_fileextension($filename);
	
	foreach($icons as $icon => $extensions)
		foreach($extensions as $extension)
			if($extension == $fileextension)
				return $icon . '.png';
	
	//If the file extension is unknown
	return 'blank.png';
}


/* Returns the file extension */
function d_fileextension($filename)
{
	$array = explode('.', $filename);
	$array_elements = count($array) - 1;
	
	return strtolower($array[$array_elements]);
}


/* Returns file size */
function d_filesizefrombytes($filesize, $totalspace = false)
{
	$filesize /= 1024; //Bytes to kiloBytes
	$iec = array('kB', 'MB', 'GB', 'TB');
	
	$count = count($iec);
	for($x = 0; ($x < $count && ($filesize / 1024) >= 1); $x++)
		$filesize /= 1024;
	
	if($totalspace) //Round totalspace differently
		$round = 0;
	else
		$round = ($x == 0 ? 0 : 1); //Round kiloBytes differently

	return round($filesize, $round) . ' ' . $iec[$x];
}


/* Returns megabytes in bytes */
function d_megabytes2bytes($megabytes)
{
	return $megabytes * 1024 * 1024;
}


/* Returns the file last-modified date */
function d_filemodified($filename)
{
	return date('Y-m-d', filemtime($filename));
}


/* Returns the title */
function d_title($path)
{
	return implode(' &raquo; ', explode('/', $path));
}


/* Returns directory tree markup */
function d_dirtree($anchor = true)
{
	global $dir;
	
	if(empty($dir))
		return '';
	
	$directories = explode('/', $dir);
	$dircount = count($directories);
	
	//Define the variables
	$directories2 = array();
	$link = '';
	$titletag =  '';
	
	for($x = 0; $x < $dircount; $x++) {
		for($y = 0; $y <= $x; $y++)
			$link .= $directories[$y] . '/';
		$link = rtrim($link, '/');
		
		if(strlen($directories[$x]) > 16) {
				$titletag = ' title="' . $directories[$x] . '"';
				$directories[$x] = substr($directories[$x], 0, 13) . '...';
		}		
		
		if($anchor) //HTML anchor tags
			$directories2[$x] = '<a href="?dir=' . str_replace('%2F', '/', rawurlencode($link)) . '"' . (empty($titletag) ? '' : $titletag) . '>' . $directories[$x] . '</a>';
		else //No tags
			$directories2[$x] = $directories[$x];
		
		$link = ''; //Reset
	}
	
	return ' &raquo; ' . implode(' &raquo; ', $directories2);	
}


/* Returns the back button (..) path */
function d_back()
{
	global $dir;
	
	if(empty($dir))
		return '?dir=';
	
	$directories = explode('/', $dir);
	array_pop($directories);
	$path = str_replace('%2F', '/', rawurlencode(implode('/', $directories)));
	
	return '?dir=' . $path;
	
}


/* Sorting function */
function d_sort($array, $index, $order)
{
	global $dir;
	
	//If the array has elements
	if(count($array > 0)) {
		
		//Define the variables
		$dirs = array();
		$files = array();
		$sorted = array();
		
		foreach(array_keys($array) as $key) {
			$is_dir = is_dir($dir . '/' . $array[$key]['name']);
			if($is_dir && ($index == 'name' || $index == 'size' || $index == 'icon')) //Sort folders by name
				$dirs[$key] = strtolower($array[$key]['name']);
			elseif($is_dir && $index == 'modified') //Sort folders by modified
				$dirs[$key] = strtolower($array[$key]['modified']);
			elseif($index == 'icon') //Sort files by extension
				$files[$key] = d_fileextension($array[$key]['name']);
			else //Sort files by $index
				$files[$key] = strtolower($array[$key][$index]);
		}
		
		//Directory sorting
		if($dirs) {
			if($order == 'desc')
				arsort($dirs);
			else
				asort($dirs);
			
			foreach(array_keys($dirs) as $key) 
				$sorted[$key] = $array[$key];
		}
		
		//Files sorting
		if($files) {
			if($order == 'desc')
				arsort($files);
			else
				asort($files);
			
			foreach(array_keys($files) as $key) 
				$sorted[$key] = $array[$key];
		}
		
		//Sorted array
		return $sorted;
	}
	
	//If the array doesn't have any elements
	return $array;
}


/* Returns the sorting markup */
function d_sorting($of)
{
	global $dir, $languages, $language;
	
	$string = ''; //Define the variable
	if(array_key_exists($of, $languages[$language]))
		$string = $languages[$language][$of];
	
	$asc_desc = 'a'; //Default = ascending
	
	if(!empty($_GET['sort']) && $of{0} == $_GET['sort']{0})
		$asc_desc = $_GET['sort']{1};
	
	return '<a href="' . (!empty($dir) ? '?dir=' . str_replace('%2F', '/', rawurlencode($dir)) . '&amp;' : '?') . 'sort=' . $of{0} . ($asc_desc == 'd' ? 'a' : 'd') . '">' . $string . '<img src="decode/img/arrow_' . ($asc_desc == 'd' ? 'up' : 'down') . '.png" alt="*" /></a>';
}


/* Returns the used space and free space */
function d_usedfreespace()
{
	global $total_space, $cachetimeout, $cache;
	
	if(!file_exists('decode/cache.inc.php') || (filemtime('decode/cache.inc.php') + $cachetimeout * 60) < time() || empty($cache)) {
		$totalspace = d_megabytes2bytes($total_space);
		
		$used_space = d_usedspaceinbytes('.');
		$used_percent = round($used_space * 100 / $totalspace, 0);
		
		$free_space = $totalspace - $used_space;
		$free_percent = 100 - $used_percent;
		
		$cache = array(
			'used_space'	=>	d_filesizefrombytes($used_space, true),
			'used_percent'	=>	$used_percent,
			'free_space'	=>	d_filesizefrombytes($free_space, true),
			'free_percent'	=>	$free_percent,
		);
		
		//Write to cache file
		@file_put_contents('decode/cache.inc.php', '<?php' . "\r\n" . '$cache = ' . var_export($cache, true) . ';' . "\r\n" . '?>');
	}
	
	return $cache;
}


/* Returns the used space in bytes */
function d_usedspaceinbytes($dir)
{
	$filesize = 0; //Define the variable
	
	$directory = @opendir($dir);
	
	while(($filename = @readdir($directory)) !== false)
		if($filename{0} != '.') {
			$path = $dir . '/' . $filename;
			if(is_dir($path))
				$filesize += d_usedspaceinbytes($path);
			else
				$filesize += filesize($path);
		}
	
	return $filesize;
}


/* file_put_contents */
if(!function_exists('file_put_contents')) {
	function file_put_contents($filename, $data)
	{
		//If anything fucked up
		if(($handle = @fopen($filename, 'w')) === false || ($bytes_written = @fwrite($handle, $data)) === false || @fclose($handle) === false)
			return false;
		else
			return $bytes_written;
	}
}


/* Returns true if the directory name / file name is valid */
function is_valid_name($name)
{
	if(!preg_match('/^(\.|\\\\|\/)/', $name) && !preg_match('/(\/|\\\\)\./', $name)  && !preg_match('/(\\\\|\/)$/', $name))
		return true;
	else
		return false;
}


/* Returns the bytes of short php.ini values */
function return_bytes($val)
{
    $val = trim($val);
    $last = strtolower($val{strlen($val) - 1});
    switch($last) {
        // The 'G' modifier is available since PHP 5.1.0
        case 'g':
            $val *= 1024;
        case 'm':
            $val *= 1024;
        case 'k':
            $val *= 1024;
    }

    return $val;
}


/* Checks if the given string is encoded in UTF8 - by chris@w3style.co.uk */
function is_utf8($str)
{
	return preg_match('%(?:
	[\xC2-\xDF][\x80-\xBF]			# non-overlong 2-byte
	|\xE0[\xA0-\xBF][\x80-\xBF]		# excluding overlongs
	|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}	# straight 3-byte
	|\xED[\x80-\x9F][\x80-\xBF]		# excluding surrogates
	|\xF0[\x90-\xBF][\x80-\xBF]{2}		# planes 1-3
	|[\xF1-\xF3][\x80-\xBF]{3}		# planes 4-15
	|\xF4[\x80-\x8F][\x80-\xBF]{2}		# plane 16
	)+%xs', $str);
}


/* UTF8 substring */
function substr_utf8($str, $from, $len)
{
	return preg_replace('#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,' . $from.  '}' .
			    '((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,' . $len . '}).*#s',
			    '$1', $str);
}


/* UTF8 string length */
function strlen_utf8($str)
{
	$i = 0;
	$count = 0;
	$len = strlen($str);
	while($i < $len) {
		$chr = ord($str[$i]);
		$count++;
		$i++;
		if($i >= $len)
			break;
		
		if($chr & 0x80) {
			$chr <<= 1;
			while($chr & 0x80) {
				$i++;
				$chr <<= 1;
			}
		}
	}
	return $count;
}
?>